/* 
UNIVERSIDADE DO EXTREMO SUL CATARINENSE - UNESC
ALUNOS: DIEGO PEREIRA DO NASCIMENTO
        RICKIFER BARROS

DISCIPLINA: COMPILADORES
*/
#include <iostream>
#include <math.h>
#include <fstream>
#include <sstream>
#include <stack>
#include <ctype.h>


using namespace std;

int verifica_caractere(char c);
int classifica_simbolo(char palavra, char prox, int cont, int * pula, int * erro, int *cod, string *temp);
int verifica_reservadas(string temp, int *cod);
int sintatico(int cod, string token, int linha, stack<int>*pilha, int producoes[64][8], int tabParsing[70][40], int * erro, int cont);

int sintatico(int cod, string token, int linha, stack<int>*pilha, int producoes[64][8], int tabParsing[70][40], int * erro, int cont)
{
    stack<int> auxpilha;
    int x = pilha->top(), a = cod, aux;
    string y;
    
    do{
        if(y!=token)
    {
      cout << "\n====================================================";
      cout << "\nTOKEN: " <<  token << "\t\t";
    }
    cout << "\nPILHA: ";
    
    y = token;
    
    while(!pilha->empty())
    {
       cout << pilha->top() << " ";
       auxpilha.push(pilha->top());
       pilha->pop();
    }
    
    while(!auxpilha.empty())
    {
       pilha->push(auxpilha.top());
       auxpilha.pop();
    }
       if(((x<42))&&(x!=40)){
          if(x!=17)
          {
              if(x == a)
              {
                 pilha->pop();
                 break;
              }else{ cout << "\a\aErro Sintatico: " << "Linha " << '"' << cont << '"' <<" Codigo " << '"' << cod << '"' << " Token " << '"' << token << '"' << endl;
                     *erro = 1;
                     return 0;
              }
          }
          else {
               pilha->pop();
               x = pilha->top();
               }
       }
       else if(x>41)
            {
               if (tabParsing[x][a]!=0)
                {
                   pilha->pop();
                   aux = tabParsing[x][a];
                             
                   for (int i=7; i>=0; i--)
                      if ((producoes[aux-1][i])!=0){
                         pilha->push(producoes[aux-1][i]);
                   }
                   
                   x = pilha->top();   
                }
                else {cout << "Linha " << cont << "\a\a\n\n Erro Sintatico! Producao nao existe!" << endl;
                       *erro = 1;
                       return 0;
             
                }
                                        
            }
             
}while(pilha->top() != 40);
    
    if (pilha->top()==40) cout << "\a\n\nPilha vazia! Analise concluida!" << endl;
}


 int verifica_int(string temp){
     int i;     
     istringstream myStream(temp);
     myStream>>i;
     if(i > 65534) return 0;
     else
     return 1;         
          }
          
     int verifica_real(string temp){
     float i;     
     istringstream myStream(temp);
     myStream>>i;
     if(i > 100000.00) return 0;
     else
     return 1;         
          }

int main () {
  char c, prox, str[256], tipovar = 'i';
  string temp, reservadas[19] = {"program","begin","end","const","var","procedure","integer","real","string",
                             "print","if","then","else","for","to","do","while","read","endl"};
  ifstream is, isaux;  
  stack <int> pilha;
  int cont = 1, pula = 0, q = 0, nint, sair=0, erro=0, aux, cod = 0, tabParsing[70][40];
  double nreal;

      for(int i=0; i<70; i++){
		for(int j=0; j<40; j++){
			tabParsing[i][j] = 0;
      }
    }
  	
    tabParsing[42][8] = 1;
	tabParsing[43][2] = 2;
	tabParsing[43][22] = 2;
	tabParsing[44][23] = 3;
	tabParsing[45][2] = 5;
	tabParsing[45][22] = 4;
	tabParsing[46][2] = 6;
	tabParsing[47][9] = 15;
	tabParsing[47][23] = 16;
	tabParsing[48][1] = 21;
	tabParsing[48][7] = 21;
	tabParsing[48][10] = 21;
	tabParsing[48][16] = 21;
	tabParsing[48][15] = 21;
	tabParsing[48][19] = 22;
	tabParsing[48][16] = 21;
	tabParsing[48][18] = 21;
	tabParsing[48][19] = 22;
	tabParsing[48][20] = 22;
	tabParsing[48][31] = 22;
	tabParsing[49][16] = 7;
	tabParsing[50][5] = 14;
	tabParsing[50][6] = 13;
	tabParsing[50][14] = 12;
	tabParsing[51][9] = 11;
	tabParsing[51][16] = 10;
	tabParsing[51][23] = 11;
	tabParsing[52][33] = 8;
	tabParsing[52][36] = 9;
	tabParsing[53][31] = 18;
	tabParsing[53][39] = 17;
	tabParsing[54][36] = 19;
	tabParsing[54][38] = 20;
	tabParsing[55][1] = 60;
	tabParsing[55][7] = 61;
	tabParsing[55][10] = 23;
	tabParsing[55][15] = 39;
	tabParsing[55][16] = 49;
	tabParsing[55][18] = 50;
	tabParsing[56][11] = 24;
	tabParsing[56][12] = 24;
	tabParsing[56][13] = 24;
	tabParsing[56][16] = 24;
	tabParsing[56][39] = 24;
	tabParsing[57][36] = 26;
	tabParsing[57][38] = 25;
	tabParsing[58][11] = 27;
	tabParsing[58][12] = 27;
	tabParsing[58][13] = 27;
	tabParsing[58][16] = 27;
	tabParsing[58][39] = 27;
	tabParsing[59][11] = 31;
	tabParsing[59][12] = 31;
	tabParsing[59][13] = 31;
	tabParsing[59][16] = 31;
	tabParsing[59][39] = 31;
	tabParsing[60][3] = 30;
	tabParsing[60][4] = 30;
	tabParsing[60][21] = 30;
	tabParsing[60][24] = 30;
	tabParsing[60][25] = 30;
	tabParsing[60][26] = 30;
	tabParsing[60][27] = 30;
	tabParsing[60][28] = 30;
	tabParsing[60][29] = 30;
	tabParsing[60][30] = 28;
	tabParsing[60][31] = 30;
	tabParsing[60][36] = 30;
	tabParsing[60][38] = 30;
	tabParsing[60][41] = 29;
	tabParsing[61][11] = 38;
	tabParsing[61][12] = 37;
	tabParsing[61][13] = 63;
	tabParsing[61][16] = 36;
	tabParsing[61][39] = 35;
	tabParsing[62][3] = 34;
	tabParsing[62][4] = 34;
	tabParsing[62][21] = 34;
	tabParsing[62][24] = 34;
	tabParsing[62][25] = 34;
	tabParsing[62][26] = 34;
	tabParsing[62][27] = 34;
	tabParsing[62][28] = 34;
	tabParsing[62][29] = 34;
	tabParsing[62][30] = 34;
	tabParsing[62][31] = 34;
	tabParsing[62][34] = 33;
	tabParsing[62][36] = 34;
	tabParsing[62][37] = 32;
	tabParsing[62][38] = 34;
	tabParsing[62][41] = 34;
	tabParsing[63][11] = 40;
	tabParsing[63][12] = 40;
	tabParsing[63][13] = 40;
	tabParsing[63][16] = 40;
	tabParsing[63][39] = 40;
	tabParsing[64][20] = 47;
	tabParsing[64][31] = 48;
	tabParsing[65][24] = 46;
	tabParsing[65][25] = 44;
	tabParsing[65][26] = 41;
	tabParsing[65][27] = 42;
	tabParsing[65][28] = 45;
	tabParsing[65][29] = 43;
	tabParsing[66][31] = 51;
	tabParsing[66][32] = 52;
	tabParsing[66][39] = 51;
	tabParsing[67][31] = 54;
	tabParsing[67][39] = 53;
	tabParsing[68][11] = 57;
	tabParsing[68][12] = 56;
	tabParsing[68][13] = 62;
	tabParsing[68][16] = 55;
	tabParsing[69][36] = 58;
	tabParsing[69][38] = 59;
	
  pilha.push(40);
  pilha.push(42);

  
  int producoes[64][8] = {
		{8,16,31,43,44,35,0,0},//P1
		{45,46,47,0,0,0,0,0},//P2
		{23,48,19,0,0,0,0,0},//P3
		{22,16,26,12,31,45,0,0},//P4
		{17,0,0,0,0,0,0,0},//P5
		{2,49,33,50,31,51,0,0},//P6
		{16,52,0,0,0,0,0,0},//P7
		{17,0,0,0,0,0,0,0},//P8
		{36,16,52,0,0,0,0,0},//P9
		{49,33,50,31,51,0,0,0},//P10
		{17,0,0,0,0,0,0,0},//P11
		{14,0,0,0,0,0,0,0},//P12
		{6,0,0,0,0,0,0,0},//P13
		{5,0,0,0,0,0,0,0},//P14
		{9,16,53,31,44,31,47,0},//P15
		{17,0,0,0,0,0,0,0},//P16
		{39,49,33,50,54,38,0,0},//P17
		{17,0,0,0,0,0,0,0},//P18
		{36,49,33,50,0,0,0,0},//P19
		{17,0,0,0,0,0,0,0},//P20
		{55,31,48,0,0,0,0,0},//P21
		{17,0,0,0,0,0,0,0},//P22
		{10,39,56,57,38,0,0,0},//P23
		{58,0,0,0,0,0,0,0},//P24
		{17,0,0,0,0,0,0,0},//P25
		{36,56,57,0,0,0,0,0},//P26
		{59,60,0,0,0,0,0,0},//P27
		{30,59,60,0,0,0,0,0},//P28
		{41,59,60,0,0,0,0,0},//P29
		{17,0,0,0,0,0,0,0},//P30
		{61,62,0,0,0,0,0,0},//P31
		{37,61,62,0,0,0,0,0},//P32
		{34,61,62,0,0,0,0,0},//P33
		{17,0,0,0,0,0,0,0},//P34
		{39,58,38,0,0,0,0,0},//P35
		{16,0,0,0,0,0,0,0},//P36
		{12,0,0,0,0,0,0,0},//P37
		{11,0,0,0,0,0,0,0},//P38
		{15,63,4,48,64,0,0,0},//P39
		{58,65,58,0,0,0,0,0},//P40
		{26,0,0,0,0,0,0,0},//P41
		{27,0,0,0,0,0,0,0},//P42
		{29,0,0,0,0,0,0,0},//P43
		{25,0,0,0,0,0,0,0},//P44
		{28,0,0,0,0,0,0,0},//P45
		{24,0,0,0,0,0,0,0},//P46
		{20,48,0,0,0,0,0,0},//P47
		{17,0,0,0,0,0,0,0},//P48
		{16,66,0,0,0,0,0,0},//P49
		{18,16,32,58,3,58,21,48},//P50
		{67,0,0,0,0,0,0,0},//P51
		{32,58,0,0,0,0,0},//P52
		{39,68,69,38,0,0,0,0},//P53
		{17,0,0,0,0,0,0,0},//P54
		{16,0,0,0,0,0,0,0},//P55
		{12,0,0,0,0,0,0,0},//P56
		{11,0,0,0,0,0,0,0},//P57
		{36,68,69,0,0,0,0,0},//P58
		{17,0,0,0,0,0,0,0},//P59
		{1,63,21,48,0,0,0,0},//P60
		{7,39,16,38,0,0,0,0},//P61
		{13,0,0,0,0,0,0,0},//P62
		{13,0,0,0,0,0,0,0},//P63
	};

do {
  system("CLS");
  cout << " \t  ==============================" << endl;
  cout << " \t  ANALISADOR LEXICO E SINTATICO" << endl;
  cout << " \t  ==============================" << endl << endl;
  cout << "Digite o nome do arquivo a ser analisado: ";
  fflush(stdin);
  is.clear();
  cin.get(str,256);
  is.open(str);
  cout << endl;
  if (!is.is_open()){
        cout << "\a\aO nome de arquivo informado nao existe! Digite novamente." << endl;
        system("pause");
   }
  
  }while(!is.is_open());
     
  c = is.get();
  
  while((c!=EOF)&&(erro!=1))
  {
    prox = is.peek();
         
    if (pula == 1)
    {
      c = is.get();
      pula = 0;
    }  
     
    if ((c == '/')&&(prox == '/')){
      while (c != '\n'){
              c = is.get();
              prox = is.peek();
                 
       }
       cont++;
    }
    
    while ((c == '\n')||(c == ' ')||(c == '\t')){
       if(c == '\n'){ cont++;
       c = is.get();
       }
       else
       c = is.get();
    }
      

          temp = "";
                  
          switch(q)
          {                                
             
             case 0: if ((c >= '0')&&(c <= '9')){
                          q = 1;
                          break;             
                                                                                        
                     }
                        else if (((c >= 'a')&&(c <= 'z'))||((c >= 'A')&&(c <= 'Z'))){
                           q = 3;
                           break;
                        }
                            else if (c == '"'){
                                q = 4;
                                break;
                            }  
                              else if (c == '/')
                              {
                                q = 5;
                                break;       
                               }                           
                               else if ((verifica_caractere(c))!='0'){
                                 q = 2;   
                                 break;                              
                               }
                                 else if ((verifica_caractere(c))=='0'){
                                   while(c!=EOF) c = is.get();   
                                   break;                              
                                 }
                                   
                                   
                           
                     break;
                                  
             case 1:  aux = 0;
                      temp = "";
                                                              
                      while ((c != '\n')&&(c != ' ')&&(c!=EOF)&&(aux < 3)&&((c >= '0')&&(c <= '9'))||(c == '.')){
                       temp = temp + c;

                      if (tipovar == 'r') aux++;
                      if (c == '.')
                       {
                          tipovar = 'r';                         
                       }
                                              
                       c = is.get();
                     }
                      
                     
                     if(verifica_caractere(c)||((c >= 'a')&&(c <= 'z'))||((c >= 'A')&&(c <= 'Z'))||(c == '\n')||(c == ' ')||(c == EOF))
                     {
                         
                       if (tipovar == 'r')
                       {
                         if((aux > 2)||(verifica_real(temp)==0))
                         {
                           while ((c != '\n')&&(c != ' ')&&(c!=EOF))
                           {
                             temp = temp + c;
                             c = is.get();
                           }
                                   
                           cout << "\n\a\aLinha " << cont << " - " << "ERRO: NUMERO REAL ACIMA DO LIMITE PERMITIDO: " << temp << endl;
                           erro = 1;
                         }
                            else
                              sintatico(11, temp, cont, &pilha, producoes, tabParsing, &erro, cont);
                       }
                        else 
                        if(verifica_int(temp)==0){
                         cout << "\n\a\aLinha " << cont << " - " << "ERRO: NUMERO INTEIRO ACIMA DO LIMITE PERMITIDO: " << temp << endl;
                         erro = 1;
                         } else
                             sintatico(12, temp, cont, &pilha, producoes, tabParsing, &erro, cont);
                         tipovar = 'i';
                         q = 0;
                         break;
                     }
                                                              
                     /*if (tipovar == 'r')
                     {
                         if((aux > 2)||(verifica_real(temp)==0))
                         {
                           cout << "##################################################################";
                           while ((c != '\n')&&(c != ' ')&&(c!=EOF))
                           {
                             temp = temp + c;
                             c = is.get();
                           }
                                   
                           cout << "\n\a\aLinha " << cont << " - " << "ERRO: NUMERO REAL ACIMA DO LIMITE PERMITIDO: " << temp << endl;
                           erro = 1;
                         }
                            else
                              sintatico(11, temp, cont, &pilha, producoes, tabParsing, &erro, cont);
                     }
                        else 
                        if(verifica_int(temp)==0){
                         cout << "\n\a\aLinha " << cont << " - " << "ERRO: NUMERO INTEIRO ACIMA DO LIMITE PERMITIDO: " << temp << endl;
                         erro = 1;
                         } else
                             sintatico(12, temp, cont, &pilha, producoes, tabParsing, &erro, cont);*/

                     tipovar = 'i';
                     q = 0;
                     break;
           
            case 2: temp = c;
                    classifica_simbolo(c, prox, cont, &pula, &erro, &cod, &temp);
                  /*  cout << "PROX: " << prox << endl;
                    cout << temp<< endl;
                    system("pause");*/
                    sintatico(cod, temp, cont, &pilha, producoes, tabParsing, &erro, cont);
                    c = is.get();
                    q = 0;
                    break;
                    
            case 3: temp = ""; 
                    while ((c != '\n')&&(c != ' ')&&(c!=EOF)&&(verifica_caractere(c)==0)){
                       temp = temp + c;
                       aux = verifica_reservadas(temp, &cod);
                       if (aux != 0){
                           sintatico(cod, reservadas[aux-1], cont, &pilha, producoes, tabParsing, &erro, cont);
                           q = 0;
                           break;
                           }
                       c = is.get();
                    }
                    
                    if(verifica_caractere(c)==1)
                    {
                        if (aux == 0) sintatico(16, temp, cont, &pilha, producoes, tabParsing, &erro, cont);
                        q = 0;
                        break;
                    }
                    
                    if (aux == 0){
                           sintatico(16, temp, cont, &pilha, producoes, tabParsing, &erro, cont);
                            }
                    if(c == '\n'){ cont++;}
                    c = is.get();
                    q = 0;
                    break;
                    
            case 4: c = is.get();   
                    while ((c != '"')&&(c != '\n')){
                       temp = temp + c;
                       c = is.get();          
                    }
                    
                    if (c == '\n')
                    {
                       cout << "Linha " << cont <<  "\a\a\t - Erro! Literal nao foi delimitado corretamente!" << endl;
                       erro = 1;
                       break;
                    }

                    c = is.get();
                    sintatico(13, temp, cont, &pilha, producoes, tabParsing, &erro, cont);
                    q = 0;
                    break;

           case 5:  prox = is.peek();
                    if (prox == '/')
                    {
                       while (c != '\n')
                       {
                        c = is.get();
                        prox = is.peek();
                       }
                       cont++;
                    }
                    q = 0;
                    break;
                    
            default: 0;    
               
          }
                 
                
     }
  
  is.close();
  
  if (erro == 0) cout << "\nLinha " << cont << " - " << "Codigo 40 '" << '$' << "'\t\t\t Fim do arquivo" << endl;
  system("PAUSE");
}

int verifica_caractere(char c)
{
    switch(c){
        case '.': return 1;
        case ';': return 1;
        case '+': return 1;
        case '-': return 1;
        case '*': return 1;
        case '/': return 1;
        case ',': return 1;
        case '>': return 1;
        case '<': return 1;
        case ':': return 1;
        case '=': return 1;
        case '(': return 1;
        case ')': return 1;
                                                                       
        default: return 0;
    }
    return 0;
}

int verifica_reservadas(string temp, int * cod)
{
    
  if (temp == "program"){ *cod = 8; return 1;}
     else if (temp == "begin"){ *cod = 23; return 2;}
        else if (temp == "end"){ *cod = 19; return 3;}
           else if (temp == "const"){ *cod = 22; return 4; }
              else if (temp == "var"){ *cod = 2; return 5; }
                 else if (temp == "procedure"){ *cod = 9; return 6; }
                    else if (temp == "integer"){*cod = 14; return 7; }
                       else if (temp == "real"){ *cod = 6; return 8; }
                          else if (temp == "string"){ *cod = 5; return 9; }
                             else if (temp == "print"){ *cod = 10; return 10; }
                                else if (temp == "if"){ *cod = 15; return 11; }
                                   else if (temp == "then"){ *cod = 4; return 12; }
                                      else if (temp == "else"){ *cod = 20; return 13; }
                                         else if (temp == "for"){ *cod = 18; return 14; }
                                            else if (temp == "to"){ *cod = 3; return 15; }
                                               else if (temp == "do"){ *cod = 21; return 16; }
                                                  else if (temp == "while"){ *cod = 1; return 17; }
                                                     else if (temp == "read"){ *cod = 7; return 18; }
                                                        else if (temp == "endl"){ *cod = 8; return 19; }
return 0;  
}
        

int classifica_simbolo(char c, char prox, int cont, int * pula, int * erro, int *cod, string *temp)
{
    switch(c){
       case '.': *cod = 35; *temp = c;
                 break;
                 
       case ',': *cod = 36; *temp = c;
                 break;
                 
       case ';': *cod = 31; *temp = c;
                 break;
                 
       case '/': *cod = 34; *temp = c;
                 break;
                 
       case '*': *cod = 37; *temp = c;
                 break;
                 
       case '-': *cod = 41; *temp = c;
                 break;
                 
       case '+': *cod = 30; *temp = c;
                 break;

       case '>': if (prox == '='){
                   *cod = 24; *temp = c + prox;
                   *pula = 1;
                 }
                   else{
                     *cod = 25; *temp = c;
                   }
                 break;
                 
       case '<': if (prox == '='){
                   *cod = 28; *temp = c + prox;
                   *pula = 1;
                 }
                   else if (prox == '>'){
                      *cod = 27; *temp = c + prox;
                      *pula = 1;
                   } 
                     else{
                       *cod = 29; *temp = c;   
                     }
                     
                 break;
                 
       case '=':  *cod = 26; *temp = c;
                  break;
                   
       case ')': *cod = 38; *temp = c;
                 break;
                 
       case '(': *cod = 39; *temp = c;
                 break;

       case ':': if (prox == '='){
                   *cod = 32; *temp = *temp + prox;
                   *pula = 1;
                 }else{
                    *cod = 33; *temp = c;
                    }
                 break;

               
       default: if ((c != ' ')&&(c != '\n')){
                   cout << "Linha " << cont <<  "\a\a\t - Erro! Caracter Invalido! - " << "'" << c << "'" << endl;
                   *erro = 1;
                   break;
                }
     }
       
}
